﻿#region File Header
//-----------------------------------------------------------------------------
// SibLib
//
// Copyright (C) 2010 Julien Villers
// This program is distributed under the terms of the 
// GNU Lesser General Public License (LGPL).
// See Docs/lgpl.txt and Docs/gpl.txt
//-----------------------------------------------------------------------------
#endregion

using System;
using System.Xml;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using SibLib.Entities;

namespace SibLib.Render
{
    /// <summary>
    /// Component for GameplayObject descendants to draw a simple textured quad.
    /// Manages size, hotspot, scale, Z, etc.
    /// </summary>
    public class Sprite : ISaveable
    {
        #region Members
        protected GameplayObject m_Object;
        protected Texture2D m_Texture;
        private float m_Scale;
        #endregion

        #region Properties
        public GameplayObject Object
        {
            get { return m_Object; }
            set { m_Object = value; }
        }
        public string Name
        {
            get;
            set;            // Note: careful with that!
        }
        /// <summary>
        /// Center of texture.
        /// </summary>
        public Vector2 Center
        {
            get;
            private set;
        }
        public float Scale
        {
            get { return m_Scale; }
            set { m_Scale = value; }
        }
        public Color Color
        {
            get;
            set;
        }
        public float Z
        {
            get;
            set;
        }
        public Texture2D Texture
        {
            get { return m_Texture; }
        }
        #endregion

        #region Size Accessors

        // Size accessors
        /// <summary>
        /// Return width, using scale.
        /// </summary>
        public float Width
        {
            get { return m_Texture.Width * Scale; }
        }
        /// <summary>
        /// Return height, using scale.
        /// </summary>
        public float Height
        {
            get { return m_Texture.Height * Scale; }
        }
        #endregion

        #region Construction

        public Sprite() :
            this(null, null)
        {
        }

        public Sprite(GameplayObject obj) :
            this(obj, null)
        {
        }

        public Sprite(GameplayObject obj, string name)
        {
            m_Object = obj;
            Name = name;
            
            Scale = 1.0f;
            Color = Color.White;
        }
        #endregion

        #region Content loading

        public void LoadContent(ContentManager content)
        {
            m_Texture = content.Load<Texture2D>("Textures/" + Name);
            Center = new Vector2(m_Texture.Width / 2.0f, m_Texture.Height / 2.0f);

            /*if (Constants.SHOW_SPRITE_COLLBOX)
            {
                int texCount = m_Texture.Width * m_Texture.Height;
                Color[] texData = new Color[texCount];
                m_Texture.GetData<Color>(texData);
                for (int idx = 0; idx != texCount; idx++)
                    if (texData[idx].A == 0)
                        texData[idx] = new Color(Color.Pink, 128);
                m_Texture.SetData<Color>(texData);
            }*/
        }

        public float ComputeRadius()
        {
            return Math.Max(Center.X, Center.Y) * Scale;
        }

        public void ComputeRadius(out float radius)
        {
            radius = ComputeRadius();
        }

        public void ComputeCollisionMap(ref byte[] colMap)
        {
            ComputeCollisionMap(m_Texture, ref colMap);
        }

        public static void ComputeCollisionMap(Texture2D texture, ref byte[] colMap)
        {
            int texCount = texture.Width * texture.Height;
            Color[] texData = new Color[texCount];
            texture.GetData<Color>(texData);
            colMap = new byte[texCount];          // TODO: could be size-optimized by a factor 8, at the expense of an added access cost at runtime.
            for (int idx = 0; idx != texCount; idx++)
                colMap[idx] = texData[idx].A;
            texData = null;
        }

        #endregion

        #region Drawing

        public void Draw(SpriteBatch spriteBatch, float timeFactor)
        {
            spriteBatch.Draw(m_Texture, m_Object.Position, null, Color, m_Object.Rotation, Center, Scale, SpriteEffects.None, Z);
        }

        #endregion

        #region ISaveable

        public virtual void SaveState(XmlDocument doc, XmlNode rootNode)
        {
            XmlNode spriteNode = doc.CreateElement("Sprite");

            XmlAttribute attr = doc.CreateAttribute("Name");
            attr.Value = Name;
            spriteNode.Attributes.Append(attr);

            attr = doc.CreateAttribute("Scale");
            attr.Value = Scale.ToString();
            spriteNode.Attributes.Append(attr);

            attr = doc.CreateAttribute("Color");
            attr.Value = Color.PackedValue.ToString();
            spriteNode.Attributes.Append(attr);

            attr = doc.CreateAttribute("Z");
            attr.Value = Z.ToString();
            spriteNode.Attributes.Append(attr);
            
            rootNode.AppendChild(spriteNode);
        }

        public virtual void LoadState(XmlNode spriteNode)
        {
            int idx = 0;
            Name = spriteNode.Attributes[idx++].Value;
            Scale = float.Parse(spriteNode.Attributes[idx++].Value);            
            Color = Conversions.UintToColor(uint.Parse(spriteNode.Attributes[idx++].Value));
            Z = float.Parse(spriteNode.Attributes[idx++].Value);
        }

        #endregion
    }
}
